// ds_extensions.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing designer extensions
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"

//@ SEC 2
//@ CHA Designer Get Format Info
//@ COD DesignerGetFormatInfo
TRANSACTION_CODE( DesignerGetFormatInfo ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* format_buffer = NULL;
	XCBuffer* field_desc = NULL;
	XCBuffer* detail = NULL;
	XCBuffer* msg_defn = NULL;
	XCBuffer* LitGroup = NULL;
	XCBuffer* LiteralVal = NULL;
	XCDBStatement* stmt = NULL;
	XCDBStatement* stmt2 = NULL;

	//@ GRS Start the transaction
	START_TXN( DesignerGetFormatInfo );

		//@ Create a DATA_STRUCTURES buffer
		TransBuf = App->CreateBuffer( FMT_DATA_STRUCTURES, false );

		//@ Create a FORMAT_DESCRIPTOR buffer
		format_buffer = App->CreateBuffer( FMT_FORMAT_DESCRIPTR, true );

		//@ Create a FIELD_DESCRIPTOR buffer
		field_desc = App->CreateBuffer( FMT_FIELD_DESCRIPTOR, true );

		//@ Create a MSG_DEFN buffer
		msg_defn = App->CreateBuffer( FMT_MSG_DEFN, true );

		//@ Create a LITERAL_VALUES buffer
		LiteralVal = App->CreateBuffer( FMT_LITERAL_VALUES );

		//@ Create a LIT_RELATE buffer
		LitGroup = App->CreateBuffer( FMT_LIT_RELATE, false );

		//@ Move supplied buffer information into transaction buffer
		TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Check for validation errors
		txnvars.Errors->Check();

		START_DB_TXN();
			//@ SUB DSGetFieldFormatNames to translate format name into a format number
			DSGetFieldFormatNames( &txnvars, TransBuf, false, format_buffer );
			txnvars.Errors->Check();

			//@ Move data from DATA_STRUCTURES record back to the screen
			txnvars.buffer->MoveCorresponding( TransBuf, txnvars.Errors );

			//@ Move FORMAT_TYPE from format_buffer into DATA_TYPE
			txnvars.buffer->MoveUnlikeField( FLD_DATA_TYPE, format_buffer, FLD_FORMAT_TYPE );
			txnvars.Errors->Check();

			//@ Send the header buffer back to the host
			App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

			//@ Check if DATA_STRUCTURES record exists
			stmt = DataStructureReviewFormat( TransBuf, &txnvars );
			if (!stmt->Eof()) {
				int child = txnvars.buffer->GetChildFormat();
				if (child) {
					//@ Create the detail buffer
					detail = App->CreateBuffer( child, false );

					//@ For each DATA_STRUCTURE record:
					while (!stmt->Eof()) {
						//@ GRS
						txnvars.Errors->Check();
						detail->Clear();

						//@ SUB LookupNameFromNumber to translate number to name
						LookupNameFromNumber( &txnvars, TransBuf, detail, FLD_FIELD_NUMBER, FLD_FIELD_NAME, FMT_FIELD_DESCRIPTOR );
						txnvars.Errors->Check();

						//@ Read Field descriptor record for defaults and message #
						field_desc->MoveCorresponding( TransBuf, txnvars.Errors );
						if (!FieldDescRetrieve( field_desc, &txnvars ))
							RAISETOOLSERROR( 1 );

						//@ Move corresponding values from field_descriptor into msg_defn
						msg_defn->MoveCorresponding( field_desc, txnvars.Errors );
						msg_defn->MoveUnlikeField( FLD_MSG_NBR, field_desc, FLD_DESC_MESSAGE );

						//@ SUB MessageDefnRetrieve to retrieve message value
						if (MessageDefnRetrieve( msg_defn, &txnvars )) {
							detail->MoveCorresponding( msg_defn, txnvars.Errors, true );
						} else {
							XCField* msg_text = detail->GetField( FLD_MSG_TEXT );
							if (msg_text)
								msg_text->MoveField( field_desc->GetField( FLD_FIELD_NAME ) );
						};

						//@ Move field descriptor data into result buffer
						detail->MoveCorresponding( field_desc, txnvars.Errors, true );

						//@ Move data-structure data into result buffer
						detail->MoveCorresponding( TransBuf, txnvars.Errors );

						//@ If this is a literal value, then return the valid literal values
						XCField* lit_values = detail->GetField( FLD_LIT_VALUES );
						if (TransBuf->GetField( FLD_DATA_TYPE )->GetLong(true) == LITERAL_STRING) {
							char* values = (char*)lit_values->GetOffset();
							*values = 0;

							// Append blank value if needed
							if (TransBuf->GetField( FLD_DESCRIPTOR_FLAGS )->GetLong() & 512)
								strcpy( values, " |" );

							LitGroup->MoveCorresponding( txnvars.buffer, txnvars.Errors );
							LitGroup->MoveUnlikeField( FLD_LIT_GROUP_NBR, TransBuf, FLD_DECIMAL_PLACES );

							bool first = true;
//							int counter = 0;
							stmt2 = GetLitGroup( LitGroup, &txnvars );
							while (!stmt2->Eof()) {
								LiteralVal->MoveCorresponding( txnvars.buffer, txnvars.Errors );
								LiteralVal->MoveCorresponding( LitGroup, txnvars.Errors );
								LiteralValueRetrieve( LiteralVal, &txnvars );

								char temp[ 255 ];
								XCField* lit = LiteralVal->GetField( FLD_LITERAL );

								lit->GetString( temp );
//								printf( "\t%3d LITERAL VALUE: '%s'\n", counter, temp );
//								counter++;

								if (!first)
									strcat( values, "|" );
								strcat( values, temp );

								first = false;
								stmt2->MoveNext();
							};
							stmt2->Release();
							stmt2 = NULL;
						} else
							lit_values->Clear();

						//@ Return detail buffer information to host
						App->TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
						stmt->MoveNext();
						//@ GRE
					};
				};
			};
		END_DB_TXN();

		CLEANUP_TXN()
			App->CleanupObjects( 9, &TransBuf, &format_buffer, &field_desc, &detail, &msg_defn, &LitGroup, &LiteralVal, &stmt, &stmt2 );
		END_TXN();
};



//@ SEC 2
//@ CHA Designer Get Messages
//@ COD DesignerGetMessages
TRANSACTION_CODE( DesignerGetMessages ) {
	XCBuffer* Message_Defn = NULL;

	//@ GRS Start the transaction
	START_TXN( DesignerGetMessages );

		//@ Create a MESSAGE_DEFN buffer
		Message_Defn = App->CreateBuffer( FMT_MSG_DEFN, false );

		//@ Move supplied buffer information into transaction buffer
		Message_Defn->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Check for validation errors
		txnvars.Errors->Check();

		START_DB_TXN();
			ValidateAppNumber( &txnvars );

			//@ Send back header information
			App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

			//@ For each child buffer,
			for (int i=0; i<txnvars.detailcount; i++) {
				XCBuffer* detail = txnvars.detail[ i ];

				//@ Move corresponding values from detail record to Message_Defn record
				Message_Defn->MoveCorresponding( detail, txnvars.Errors );

				//@ SUB MessageDefnRetrieve return 
				if (MessageDefnRetrieve( Message_Defn, &txnvars )) {
					//@ Move corresponding values from Message_Defn info detail record
					detail->MoveCorresponding( Message_Defn, txnvars.Errors );
				} else {
					detail->GetField( FLD_MSG_TEXT )->SetString( "#UNDEFINED#" );
				};

				//@ Return detail buffer information to host
				App->TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
			};

		END_DB_TXN();

		CLEANUP_TXN()
			App->CleanupObjects( 1, &Message_Defn );
		END_TXN();
};




//@ SEC 2
//@ CHA Designer Get Defaults
//@ COD DesignerGetDefaults
TRANSACTION_CODE( DesignerGetDefaults ) {
	XCBuffer* Field_Descr = NULL;
	XCBuffer* Literal_Values = NULL;
	XCBuffer* Literal_Relate = NULL;
	XCDBStatement* stmt = NULL;

	//@ GRS Start the transaction
	START_TXN( DesignerGetDefaults );

		//@ Create a MESSAGE_DEFN buffer
		Field_Descr = App->CreateBuffer( FMT_FIELD_DESCRIPTOR, false );

		//@ Move supplied buffer information into transaction buffer
		Field_Descr->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Create a LITERAL_VALUES buffer
		Literal_Values = App->CreateBuffer( FMT_LITERAL_VALUES, false );

		//@ Move supplied buffer information into literal values buffer
		Literal_Values->MoveCorresponding( txnvars.buffer, txnvars.Errors );
		XCField* lit_val = Literal_Values->GetField( FLD_LITERAL );

		//@ Create a LITERAL_RELATE buffer
		Literal_Relate = App->CreateBuffer( FMT_LIT_RELATE, false );
		
		//@ Move supplied buffer information into literal relate buffer
		Literal_Relate->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Check for validation errors
		txnvars.Errors->Check();

		//@ Start the database transaction
		START_DB_TXN();
			XCSQLGen* query = txnvars.query;

			ValidateAppNumber( &txnvars );

			//@ Send back header information
			App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

			XCJoin join;
			join.buffer = Literal_Values;
			join.predicate = new XCCompare[2];
			join.predicate_count = 2;
			join.predicate[0].field = Literal_Relate->GetField( FLD_APPL_NBR );
			join.predicate[0].field2 = Literal_Values->GetField( FLD_APPL_NBR );
			join.predicate[1].field = Literal_Relate->GetField( FLD_LITERAL_NUMBER );
			join.predicate[1].field2 = Literal_Values->GetField( FLD_LITERAL_NUMBER );

			//@ For each child buffer,
			for (int i=0; i<txnvars.detailcount; i++) {
				XCBuffer* detail = txnvars.detail[ i ];
				XCField* value = detail->GetField( FLD_FIELD_VALUE );

				//@ Move corresponding values from detail record to Field_Descr record
				Field_Descr->MoveCorresponding( detail, txnvars.Errors );

				//@ SUB FieldDescRetrieve return 
				if (FieldDescRetrieve( Field_Descr, &txnvars )) {
					//@ Move corresponding values from Field_Descr info detail record
					detail->MoveCorresponding( Field_Descr, txnvars.Errors );

					//@ Set the group number
					Literal_Relate->GetField( FLD_LIT_GROUP_NBR )->MoveField( Field_Descr->GetField( FLD_DECIMAL_PLACES ) );

					//@ Special case for literals, if language number not the default
					int type = detail->GetField( FLD_DATA_TYPE )->GetLong( true );
					if ((type == LITERAL_VAL || type == LITERAL_STRING) && XCGetLanguage()) {
						//@ Lookup the literal value for this language, if not blank
						if (!value->IsBlank()) {
							XCField* lang_id = Literal_Values->GetField( FLD_LANG_ID );

							//@ Set LANG_ID to false
							lang_id->SetLong(0);

							lit_val->MoveField( Field_Descr->GetField( FLD_FIELD_VALUE ) );

							//@ Query for Literal_Number
							query->MakeSELECT( Literal_Relate );
							query->AddJOIN( &join );
							query->AddWHERE( 4,
								Literal_Values->GetField( FLD_APPL_NBR ),
								lang_id,
								lit_val,
								Literal_Relate->GetField( FLD_LIT_GROUP_NBR ) );
							txnvars.dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

							//@ Set LANG_ID field on Literal_Values
							lang_id->SetLong( XCGetLanguage() );

							//@ SUB LiteralValueRetrieve Requery for literal number
							if (LiteralValueRetrieve( Literal_Values, &txnvars )) {
								value->MoveField( lit_val );
							} else {
								value->Clear();
							};
						};
					};
				} else {
					value->Clear();
					txnvars.Errors->Add( ERR_FLD_NOT_FOUND, SEV_WARNING, FLD_FIELD_NUMBER, 1, value );
				};

				//@ Return detail buffer information to host
				App->TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
			};

		END_DB_TXN();

		CLEANUP_TXN()
			App->CleanupObjects( 4, &Field_Descr, &Literal_Values, &Literal_Relate, &stmt );
		END_TXN();
};




//@ SEC 2
//@ CHA Designer Get Languages
//@ COD DesignerGetLanguages
TRANSACTION_CODE( DesignerGetLanguages ) {
	XCBuffer* Lang_Defn = NULL;
	XCDBStatement* stmt = NULL;

	//@ GRS Start the transaction
	START_TXN( DesignerGetLanguages );

		//@ Create a LANGUAGE_DEFN buffer
		Lang_Defn = App->CreateBuffer( FMT_LANGUAGE_DEFN, false );

		//@ Check for validation errors
		txnvars.Errors->Check();

		START_DB_TXN();
			XCSQLGen* query = txnvars.query;

			//@ Send back header information
			App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

			query->MakeSELECT( Lang_Defn );
			stmt = txnvars.dbtxn->ExecuteSQL( query );
			while (!stmt->Eof()) {
				App->TransResponse( txnvars.result, Lang_Defn, TRANS_DETAIL_TYPE );
				stmt->MoveNext();
			};
		END_DB_TXN();

	CLEANUP_TXN()
		App->CleanupObjects( 2, &Lang_Defn, &stmt );
	END_TXN();
};
